package com.surfilter.platform.base.service;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.surfilter.modules.syslog.model.PlSyslogModel;
import com.surfilter.modules.syslog.service.SysLogMgrService;
import com.surfilter.platform.base.exception.CustomException;
import com.surfilter.platform.base.exception.ExceptionBase;
import com.surfilter.platform.base.exception.SystemException;
import com.surfilter.platform.base.model.ActionPermission;
import com.surfilter.platform.base.model.Constants;
import com.surfilter.platform.base.model.MethodWrap;
import com.surfilter.platform.base.model.ResultCode;
import com.surfilter.platform.base.util.MethodUtil;
import com.surfilter.platform.base.util.ResultDataUtil;
import com.surfilter.platform.data.model.UserModel;

public class ServiceImpl {
	/**
	 * 请求分发，调用业务方法，流程：
	 * 
	 * 1.根据module,action定位业务方法
	 * 2.反射调用业务方法
	 * 3.包装方法返回值,处理异常
	 * 4.输出结果至客户端
	 * 5.记录业务日志
	 * 
	 * @param request
	 * @param response
	 * @throws IOException
	 */
	
	private static SysLogMgrService logSer ;
	
	public static void doService(HttpServletRequest request,
			HttpServletResponse response) throws IOException {
		PlSyslogModel syslogModel = null;
		long begin  = 0l;
		try {
			response.setHeader(   "Content-Type"   ,   "text/html;charset=utf-8" );
			String moduleName = request.getParameter(Constants.MODULE_TAG);
			String actionName = request.getParameter(Constants.ACTION_TAG);

			if (moduleName != null && moduleName.trim().length() > 0
					&& actionName != null && actionName.trim().length() > 0) {
				ServiceBase object = null;
				MethodWrap methodWrap = null;
				//定位服务类和方法
				object = (ServiceBase)ServiceContext
						.getServiceObjectByModuleName(moduleName);
				methodWrap = ServiceContext
						.getMethodWrapByModuleNameAndActionName(moduleName,
								actionName);
				if (object != null && methodWrap != null
						&& methodWrap.getMethod() != null) {
					syslogModel = getSysLogInfo(request,methodWrap);
					begin = System.currentTimeMillis();
					//反射调用业务方法
					Object result = MethodUtil.InvokeServiceMethod(object,
							methodWrap, request,response);
					long cost = System.currentTimeMillis() - begin;
					syslogModel.setCost((int)cost);
					//封装调用结果
					Map<String, Object> extraParams = null;
					String isPage = request.getParameter("isPage");
					//在结果中加入分页信息
					if (isPage != null && isPage.equals("true")) {
						String countName = actionName + "Count";
						MethodWrap countMethodWrap = ServiceContext
								.getMethodWrapByModuleNameAndActionName(
										moduleName, countName);
						Object count = MethodUtil.InvokeServiceMethod(object,
								countMethodWrap, request,response);
						extraParams = new HashMap<String, Object>();
						extraParams.put("total", count);
					}
					String resultData = ResultDataUtil.wrapResultData(true,
							ResultCode.SUCCESS, Constants.MSG_BLANK, result,
							extraParams);
					response.getWriter().write(resultData);
					response.getWriter().flush();
					response.getWriter().close();
					syslogModel.setResultCode(ResultCode.SUCCESS);
					syslogModel.setDescription("操作成功");
					//记录业务日志
					doLogSysLog(syslogModel);
				} else {
					throw new SystemException("Service Or Method Not Found");
				}
			} else {
				throw new SystemException(
						"RequestData Not Contains Module's Name And Action's Name");
			}
		} catch (Throwable e) {
			if(!(e instanceof CustomException)){
				e.printStackTrace();
			}
			String resultData = ResultDataUtil.wrapResultData((Exception)e);
			response.getWriter().write(resultData);
			response.getWriter().flush(); 
			response.getWriter().close();
			long cost = System.currentTimeMillis() - begin;
			syslogModel.setCost((int)cost);
			PlSyslogModel model = getErrorInfo(e);
			syslogModel.setResultCode(model.getResultCode());
			syslogModel.setDescription(model.getDescription());
			doLogSysLog(syslogModel);
		}
	}
	
	
	
	/**
	 * 将系统日志持久化
	 * @param syslogModel
	 */
	private static void doLogSysLog(PlSyslogModel syslogModel) {
		if(!syslogModel.isSkipLogging()){
			if(logSer == null)
				logSer = SpringContextUtil.getBean(SysLogMgrService.class);
			logSer.addPlSyslog(syslogModel);
		}
	}



	/**
	 * 获取系统业务日志信息
	 * @param req
	 * @param methodWrap
	 */
	private static PlSyslogModel getSysLogInfo(HttpServletRequest req,MethodWrap methodWrap){
		PlSyslogModel sysLogModel = new PlSyslogModel();
		HttpSession session = req.getSession();
		UserModel user = (UserModel)session.getAttribute(Constants.LOGIN_USER_TAG);
		if(user == null){
			user = new UserModel();
			user.setUserName("未登录用户");
		}
		String ip = req.getRemoteHost();
		ActionPermission acp = methodWrap.getMethod().getAnnotation(ActionPermission.class);
		String actionName = acp.actionName();
		String moduleName = req.getParameter(Constants.MODULE_TAG);
		String actionRemark = acp.remark();
		if(acp.skipLogging()){
			sysLogModel.setSkipLogging(true);
		}
		String pageStr = req.getParameter("page");
		if(pageStr != null && !"1".equals(pageStr)){
			sysLogModel.setSkipLogging(true);
		}
		sysLogModel.setRemoteIp(ip);
		sysLogModel.setOperatorName(user.getUserName());
		sysLogModel.setOperatorTime(new Date());
		sysLogModel.setActionName(actionName);
		sysLogModel.setModuleName(moduleName);
		sysLogModel.setActionRemark(actionRemark);
		return sysLogModel;
	}
	/**
	 * 获取异常信息
	 * @param e
	 * @return
	 */
	private static PlSyslogModel getErrorInfo(Throwable e){
		PlSyslogModel model = new PlSyslogModel();
		String msg = null;
		int code = ResultCode.SYSTEM_ERROR_CODE;
		if(e instanceof ExceptionBase){
			msg = ((ExceptionBase)e).getCustomMsg();
			code = ((ExceptionBase)e).getErrorCode();
		}else{
			msg = ((Exception)e).getMessage();
		}
		model.setDescription(msg);
		model.setResultCode(code);
		return model;
	} 
}
